블로그_03_자동화 배포_깃헙 액션 도입
반복 작업.... 귀찮다!
블로그를 실제로 사용하려면 새 md 파일을 다시 서버에 올리는 일을 반복해야 한다.
즉, md 파일을 하나 추가하거나 수정할 때마다 서버에 SSH로 접속하고, git pull을 실행해야 한다.
만약 변경 사항이 코드와 연관된 경우에는 더 짜증난다. 똑같이 접속하고 git pull 후
다시 빌드를 진행해야 한다는 것이다. 실행 중인 프로세스를 일일히 재시작하는 것은 덤이다.
글 수정 뿐만 아니라 레이아웃이나 기능을 조금씩 수정하기 시작하면서 이 과정이 매우 번거롭다고 생각했다.
노트와 글을 쓰고 정리하는 작업 자체보다 배포 과정이 더 신경 쓰이는 상태가 되기 시작한 것이다.
문제를 정리해보니 다음과 같았다.
- 배포 과정이 모두 수동으로 이루어져 있어 실수가 발생하기 쉬웠다.
- 변경 유형에 따른 구분이 없다.(문서 파일만 수정한 경우와, 실제 코드 변경) 해결 방법은? 배포 자동화 뿐이다. 나아가 문서와 코드 변경 사항을 별도로 구분할 수 있으면 좋을 것 같다.
GitHub Actions 도입
GitHub 저장소와 연동해 배포 과정을 자동화할 수 있는 GitHub Actions를 도입했다.
구조는 매우 단순했다.
- 특정 브랜치에 코드가 푸시되면
- 미리 정의한 작업을 GitHub가 대신 실행
- 로컬에서는 코드와 글 작성에만 집중
- 배포 관련 작업은 GitHub Actions가 담당
변경 유형에 따른 배포 분리
또 모든 변경에 대해 동일한 배포 과정을 거치는 대신, 변경된 파일의 종류에 따라 작업을 나누기로 했다.
Markdown 콘텐츠만 변경된 경우
- 빌드 생략
- 수정된 콘텐츠만 서버로 전송
- 실행 중인 프로세스만 재시작
이 블로그는 경로에 md 파일만 있으면 알아서 렌더링해주기 때문에, 글 자체를 새롭게 빌드할 필요가 없다.
코드 변경이 포함된 경우
- 의존성 설치
- 전체 빌드 실행
- 빌드 결과 배포 후 프로세스 재시작
Next.js 기반이므로 코드 변경이 포함된 경우는 빌드를 다시 실행해야 한다.
이를 위해 GitHub Actions에서 파일 변경 경로를 기준으로 조건 분기를 적용했다.
불필요한 빌드를 줄이고 배포 시간을 단축할 수 있었다.
paths:
- 'content/**' # 콘텐츠(글)이 있는 폴더
- 'src/**' # 코드가 있는 폴더
GitHub Actions 도입 이후 흐름은 다음과 같이 단순해졌다.
- 로컬에서 글 또는 코드 수정
- GitHub에 푸시
- 변경 내용에 따라 자동으로 배포 방식 분류
- 서버가 pull을 통해 변경사항을 가져와서 자동으로 배포
이제 더 이상 배포를 위해 서버에 접속할 필요가 없어졌다.
빌드 시간이 길어지는 문제
이렇게 GitHub Actions를 통해 자동 배포 환경을 구축한 후
- 수동 배포로 인한 반복 작업과 피로도를 줄였다
- 변경 유형에 따라 배포 과정을 분리했다
- GitHub Actions를 통해 자동 배포 환경을 구축했다.
하지만 끝나지 않았다....
자동 배포 과정은 안정적으로 정리되었지만, 또 다른 문제가 남아 있었다.
자동 배포가 실행될 때마다 빌드 시간이 예상보다 길어지는 현상이었다.
빌드 시간이 길어지는 이유는 간단했다. 빌드 자체를 Oracle 인스턴스에서 수행했기 때문이었다.
Oracle Free Tier 인스턴스의 리소스 특성상, 서버에서 직접 빌드를 수행하면 메모리 사용량이 컸다.
(이때는 스왑 개념도 몰랐기 때문에 과부하가 올 수밖에 없었다.)
처음 구성한 자동 배포는 단순히 깃헙에 수정 내역을 푸시하고, 이것을 서버에서 pull해서 가져와 자동으로 배포하도록 구현했기 때문에 서버 자체에서 빌드를 하느라 시간이 길어질 수밖에 없던 것이다.
자동 배포 시 빌드 구조 변경
GitHub Actions(CI)를 통해 빌드를 하고,
빌드 결과물을 서버로 전송하여 배포하는 구조로 변경할 필요가 있었다.
처음에는 이 개념을 몰랐기 때문에 이해가 잘 안됐는데
빌드 산출물(.next/, public/ 등)만을 서버로 전송할 수 있다는 사실을 알고 머리가 띵한 기분이었다.
따라서 자동 배포 구조를 변경하여 GitHub Actions에서 분류와 빌드를 동시에 진행하고 이 빌드 산출물을 서버로 전송,
서버는 결과물을 받아 실행만 하는 것으로 역할을 분리했다.
결과는 GitHub Actions의 높은 성능으로 매우 빠른 빌드 → 서버는 실행만 하여 매우 빠르게 재배포(업데이트)가 가능해졌다.
결과적으로 이제는 글을 추가하거나 수정할 때마다 무거운 빌드를 하지 않아도 되고,
배포 비용을 최소화하면서도 일관된 구조를 유지할 수 있게 된 것이다.
환경과 책임을 분리하는 구조
이 구조가 도커의 개념과 유사하다고 생각했다.
빌드 환경과 실행 환경을 분리하고, 서버는 이미 만들어진 결과물만 실행한다는 점에서 동일한 사고방식이 아닌가?
도커 공부 중이었는데, 헷갈리던 부분에 기본 가닥이 잡힌 것 같다.